Skip to content

fix: load fontconfig via dlopen on Linux and fix bundled fallback font#21

Merged
rrbe merged 2 commits into
masterfrom
fix/linux-fontconfig-dlopen
Jun 8, 2026
Merged

fix: load fontconfig via dlopen on Linux and fix bundled fallback font#21
rrbe merged 2 commits into
masterfrom
fix/linux-fontconfig-dlopen

Conversation

@rrbe

@rrbe rrbe commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Why

Two Linux-only problems that bit cargo install termdown on bare servers:

  1. Build required the fontconfig dev package + pkg-config. font-kit linked fontconfig at build time, so cargo install termdown failed on any machine without libfontconfig1-dev / fontconfig-devel.
  2. The bundled fallback font was a corrupt HTML file — shipped that way since v0.1.0. It only ever loads when no system font resolves, so on dev machines it stayed invisible; on a font-less server it meant headings silently degraded to plain text.

What changed

  • dlopen fontconfig on Linux — switch font-kit to the source-fontconfig-dlopen feature so building needs neither the fontconfig dev package nor pkg-config; the shared library is loaded lazily at runtime. macOS/Windows use CoreText/DirectWrite and never pull fontconfig.
  • Graceful runtime degradation — probe for libfontconfig.so.1 / libfontconfig.so via dlopen before constructing SystemSource. If it's missing at runtime, fall back to the bundled font instead of panicking deep in the FFI layer.
  • Real fallback font — replace the corrupt asset with OFL-licensed Source Serif 4 SemiBold (license added as fonts/LICENSE-SourceSerif4.md), plus a regression test that parses the bundled font and checks it renders a glyph, so a bad asset can't regress.
  • CI now installs only the runtime libfontconfig1 (no -dev), proving the build doesn't need the dev package while still exercising the runtime font-discovery path.
  • Docs — README Linux note + CHANGELOG [Unreleased] entry.

Test plan

  • make check green locally (fmt-check + clippy -D warnings + tests).
  • New bundled_fallback_font_is_a_valid_font test guards the asset.
  • CI Linux job installs runtime-only libfontconfig1.

🤖 Generated with Claude Code

rrbe and others added 2 commits June 8, 2026 21:21
Two Linux-only fixes that together let `cargo install termdown` work on
bare servers and make headings degrade gracefully when no system font is
available:

- font-kit now uses the `source-fontconfig-dlopen` feature on Linux, so
  building requires neither the fontconfig dev package nor pkg-config; the
  shared library is loaded lazily at runtime. CI now installs only the
  runtime `libfontconfig1` to prove this.
- Probe for libfontconfig via dlopen before using SystemSource; when it's
  absent at runtime, degrade to the bundled font instead of panicking deep
  in the FFI layer.
- Replace the corrupt bundled fallback (an HTML file shipped as a font
  since v0.1.0) with OFL-licensed Source Serif 4 SemiBold, and add a test
  that parses the bundled font so a bad asset can't regress.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
font-kit pulls freetype-sys unconditionally on Linux (no feature gates it
off), and freetype-sys links the host libfreetype whenever pkg-config finds
a freetype2.pc. The ubuntu-latest image ships that .pc but not the matching
libfreetype.so dev symlink, so dropping libfontconfig1-dev broke linking
with `unable to find library -lfreetype` (clippy passed because it never
links).

Point pkg-config at an empty dir in the Linux CI steps so freetype-sys
compiles its bundled copy statically instead — the same path a real
`cargo install` takes on a bare server with no dev packages. Document the
freetype-from-source behavior in README/CHANGELOG.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rrbe rrbe merged commit 5f38b37 into master Jun 8, 2026
5 checks passed
@rrbe rrbe deleted the fix/linux-fontconfig-dlopen branch June 8, 2026 14:00
@rrbe rrbe mentioned this pull request Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant